<!doctype html>

<html>
<head>
  <link rel="shortcut icon" href="static/images/favicon.ico" type="image/x-icon">
  <title>abstractdragdrop.js (Closure Library API Documentation - JavaScript)</title>
  <link rel="stylesheet" href="static/css/base.css">
  <link rel="stylesheet" href="static/css/doc.css">
  <link rel="stylesheet" href="static/css/sidetree.css">
  <link rel="stylesheet" href="static/css/prettify.css">

  <script>
     var _staticFilePath = "static/";
     var _typeTreeName = "goog";
     var _fileTreeName = "Source";
  </script>

  <script src="static/js/doc.js">
  </script>


  <meta charset="utf8">
</head>

<body onload="grokdoc.onLoad();">

<div id="header">
  <div class="g-section g-tpl-50-50 g-split">
    <div class="g-unit g-first">
      <a id="logo" href="index.html">Closure Library API Documentation</a>
    </div>

    <div class="g-unit">
      <div class="g-c">
        <strong>Go to class or file:</strong>
        <input type="text" id="ac">
      </div>
    </div>
  </div>
</div>

<div class="clear"></div>

<h2><a href="closure_goog_fx_abstractdragdrop.js.html">abstractdragdrop.js</a></h2>

<pre class="prettyprint lang-js">
<a name="line1"></a>// Copyright 2006 The Closure Library Authors. All Rights Reserved.
<a name="line2"></a>//
<a name="line3"></a>// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
<a name="line4"></a>// you may not use this file except in compliance with the License.
<a name="line5"></a>// You may obtain a copy of the License at
<a name="line6"></a>//
<a name="line7"></a>//      http://www.apache.org/licenses/LICENSE-2.0
<a name="line8"></a>//
<a name="line9"></a>// Unless required by applicable law or agreed to in writing, software
<a name="line10"></a>// distributed under the License is distributed on an &quot;AS-IS&quot; BASIS,
<a name="line11"></a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a name="line12"></a>// See the License for the specific language governing permissions and
<a name="line13"></a>// limitations under the License.
<a name="line14"></a>
<a name="line15"></a>/**
<a name="line16"></a> * @fileoverview Abstract Base Class for Drag and Drop.
<a name="line17"></a> *
<a name="line18"></a> * Provides functionality for implementing drag and drop classes. Also provides
<a name="line19"></a> * support classes and events.
<a name="line20"></a> *
<a name="line21"></a> * @author eae@google.com (Emil A Eklund)
<a name="line22"></a> */
<a name="line23"></a>
<a name="line24"></a>goog.provide(&#39;goog.fx.AbstractDragDrop&#39;);
<a name="line25"></a>goog.provide(&#39;goog.fx.AbstractDragDrop.EventType&#39;);
<a name="line26"></a>goog.provide(&#39;goog.fx.DragDropEvent&#39;);
<a name="line27"></a>goog.provide(&#39;goog.fx.DragDropItem&#39;);
<a name="line28"></a>
<a name="line29"></a>goog.require(&#39;goog.dom&#39;);
<a name="line30"></a>goog.require(&#39;goog.dom.classes&#39;);
<a name="line31"></a>goog.require(&#39;goog.events&#39;);
<a name="line32"></a>goog.require(&#39;goog.events.Event&#39;);
<a name="line33"></a>goog.require(&#39;goog.events.EventHandler&#39;);
<a name="line34"></a>goog.require(&#39;goog.events.EventTarget&#39;);
<a name="line35"></a>goog.require(&#39;goog.events.EventType&#39;);
<a name="line36"></a>goog.require(&#39;goog.fx.Dragger&#39;);
<a name="line37"></a>goog.require(&#39;goog.fx.Dragger.EventType&#39;);
<a name="line38"></a>goog.require(&#39;goog.math.Box&#39;);
<a name="line39"></a>goog.require(&#39;goog.math.Coordinate&#39;);
<a name="line40"></a>goog.require(&#39;goog.style&#39;);
<a name="line41"></a>
<a name="line42"></a>
<a name="line43"></a>
<a name="line44"></a>/**
<a name="line45"></a> * Abstract class that provides reusable functionality for implementing drag
<a name="line46"></a> * and drop functionality.
<a name="line47"></a> *
<a name="line48"></a> * This class also allows clients to define their own subtargeting function
<a name="line49"></a> * so that drop areas can have finer granularity then a singe element. This is
<a name="line50"></a> * accomplished by using a client provided function to map from element and
<a name="line51"></a> * coordinates to a subregion id.
<a name="line52"></a> *
<a name="line53"></a> * This class can also be made aware of scrollable containers that contain
<a name="line54"></a> * drop targets by calling addScrollableContainer. This will cause dnd to
<a name="line55"></a> * take changing scroll positions into account while a drag is occuring.
<a name="line56"></a> *
<a name="line57"></a> * @extends {goog.events.EventTarget}
<a name="line58"></a> * @constructor
<a name="line59"></a> */
<a name="line60"></a>goog.fx.AbstractDragDrop = function() {
<a name="line61"></a>  goog.base(this);
<a name="line62"></a>
<a name="line63"></a>  /**
<a name="line64"></a>   * List of items that makes up the drag source or drop target.
<a name="line65"></a>   * @type {Array.&lt;goog.fx.DragDropItem&gt;}
<a name="line66"></a>   * @protected
<a name="line67"></a>   * @suppress {underscore}
<a name="line68"></a>   */
<a name="line69"></a>  this.items_ = [];
<a name="line70"></a>
<a name="line71"></a>  /**
<a name="line72"></a>   * List of associated drop targets.
<a name="line73"></a>   * @type {Array.&lt;goog.fx.AbstractDragDrop&gt;}
<a name="line74"></a>   * @private
<a name="line75"></a>   */
<a name="line76"></a>  this.targets_ = [];
<a name="line77"></a>
<a name="line78"></a>  /**
<a name="line79"></a>   * Scrollable containers to account for during drag
<a name="line80"></a>   * @type {Array.&lt;goog.fx.ScrollableContainer_&gt;}
<a name="line81"></a>   * @private
<a name="line82"></a>   */
<a name="line83"></a>  this.scrollableContainers_ = [];
<a name="line84"></a>
<a name="line85"></a>};
<a name="line86"></a>goog.inherits(goog.fx.AbstractDragDrop, goog.events.EventTarget);
<a name="line87"></a>
<a name="line88"></a>
<a name="line89"></a>/**
<a name="line90"></a> * Minimum size (in pixels) for a dummy target. If the box for the target is
<a name="line91"></a> * less than the specified size it&#39;s not created.
<a name="line92"></a> * @type {number}
<a name="line93"></a> * @private
<a name="line94"></a> */
<a name="line95"></a>goog.fx.AbstractDragDrop.DUMMY_TARGET_MIN_SIZE_ = 10;
<a name="line96"></a>
<a name="line97"></a>
<a name="line98"></a>/**
<a name="line99"></a> * Flag indicating if it&#39;s a drag source, set by addTarget.
<a name="line100"></a> * @type {boolean}
<a name="line101"></a> * @private
<a name="line102"></a> */
<a name="line103"></a>goog.fx.AbstractDragDrop.prototype.isSource_ = false;
<a name="line104"></a>
<a name="line105"></a>
<a name="line106"></a>/**
<a name="line107"></a> * Flag indicating if it&#39;s a drop target, set when added as target to another
<a name="line108"></a> * DragDrop object.
<a name="line109"></a> * @type {boolean}
<a name="line110"></a> * @private
<a name="line111"></a> */
<a name="line112"></a>goog.fx.AbstractDragDrop.prototype.isTarget_ = false;
<a name="line113"></a>
<a name="line114"></a>
<a name="line115"></a>/**
<a name="line116"></a> * Subtargeting function accepting args:
<a name="line117"></a> * (Element, goog.math.Box, number, number)
<a name="line118"></a> * @type {Function}
<a name="line119"></a> * @private
<a name="line120"></a> */
<a name="line121"></a>goog.fx.AbstractDragDrop.prototype.subtargetFunction_;
<a name="line122"></a>
<a name="line123"></a>
<a name="line124"></a>/**
<a name="line125"></a> * Last active subtarget.
<a name="line126"></a> * @type {Object}
<a name="line127"></a> * @private
<a name="line128"></a> */
<a name="line129"></a>goog.fx.AbstractDragDrop.prototype.activeSubtarget_;
<a name="line130"></a>
<a name="line131"></a>
<a name="line132"></a>/**
<a name="line133"></a> * Class name to add to source elements being dragged. Set by setDragClass.
<a name="line134"></a> * @type {?string}
<a name="line135"></a> * @private
<a name="line136"></a> */
<a name="line137"></a>goog.fx.AbstractDragDrop.prototype.dragClass_;
<a name="line138"></a>
<a name="line139"></a>
<a name="line140"></a>/**
<a name="line141"></a> * Class name to add to source elements. Set by setSourceClass.
<a name="line142"></a> * @type {?string}
<a name="line143"></a> * @private
<a name="line144"></a> */
<a name="line145"></a>goog.fx.AbstractDragDrop.prototype.sourceClass_;
<a name="line146"></a>
<a name="line147"></a>
<a name="line148"></a>/**
<a name="line149"></a> * Class name to add to target elements. Set by setTargetClass.
<a name="line150"></a> * @type {?string}
<a name="line151"></a> * @private
<a name="line152"></a> */
<a name="line153"></a>goog.fx.AbstractDragDrop.prototype.targetClass_;
<a name="line154"></a>
<a name="line155"></a>
<a name="line156"></a>/**
<a name="line157"></a> * The SCROLL event target used to make drag element follow scrolling.
<a name="line158"></a> * @type {EventTarget}
<a name="line159"></a> * @private
<a name="line160"></a> */
<a name="line161"></a>goog.fx.AbstractDragDrop.prototype.scrollTarget_;
<a name="line162"></a>
<a name="line163"></a>
<a name="line164"></a>/**
<a name="line165"></a> * Dummy target, {@see maybeCreateDummyTargetForPosition_}.
<a name="line166"></a> * @type {goog.fx.ActiveDropTarget_}
<a name="line167"></a> * @private
<a name="line168"></a> */
<a name="line169"></a>goog.fx.AbstractDragDrop.prototype.dummyTarget_;
<a name="line170"></a>
<a name="line171"></a>
<a name="line172"></a>/**
<a name="line173"></a> * Whether the object has been initialized.
<a name="line174"></a> * @type {boolean}
<a name="line175"></a> * @private
<a name="line176"></a> */
<a name="line177"></a>goog.fx.AbstractDragDrop.prototype.initialized_ = false;
<a name="line178"></a>
<a name="line179"></a>
<a name="line180"></a>/**
<a name="line181"></a> * Constants for event names
<a name="line182"></a> * @type {Object}
<a name="line183"></a> */
<a name="line184"></a>goog.fx.AbstractDragDrop.EventType = {
<a name="line185"></a>  DRAGOVER: &#39;dragover&#39;,
<a name="line186"></a>  DRAGOUT: &#39;dragout&#39;,
<a name="line187"></a>  DRAG: &#39;drag&#39;,
<a name="line188"></a>  DROP: &#39;drop&#39;,
<a name="line189"></a>  DRAGSTART: &#39;dragstart&#39;,
<a name="line190"></a>  DRAGEND: &#39;dragend&#39;
<a name="line191"></a>};
<a name="line192"></a>
<a name="line193"></a>
<a name="line194"></a>/**
<a name="line195"></a> * Constant for distance threshold, in pixels, an element has to be moved to
<a name="line196"></a> * initiate a drag operation.
<a name="line197"></a> * @type {number}
<a name="line198"></a> */
<a name="line199"></a>goog.fx.AbstractDragDrop.initDragDistanceThreshold = 5;
<a name="line200"></a>
<a name="line201"></a>
<a name="line202"></a>/**
<a name="line203"></a> * Set class to add to source elements being dragged.
<a name="line204"></a> *
<a name="line205"></a> * @param {string} className Class to be added.
<a name="line206"></a> */
<a name="line207"></a>goog.fx.AbstractDragDrop.prototype.setDragClass = function(className) {
<a name="line208"></a>  this.dragClass_ = className;
<a name="line209"></a>};
<a name="line210"></a>
<a name="line211"></a>
<a name="line212"></a>/**
<a name="line213"></a> * Set class to add to source elements.
<a name="line214"></a> *
<a name="line215"></a> * @param {string} className Class to be added.
<a name="line216"></a> */
<a name="line217"></a>goog.fx.AbstractDragDrop.prototype.setSourceClass = function(className) {
<a name="line218"></a>  this.sourceClass_ = className;
<a name="line219"></a>};
<a name="line220"></a>
<a name="line221"></a>
<a name="line222"></a>/**
<a name="line223"></a> * Set class to add to target elements.
<a name="line224"></a> *
<a name="line225"></a> * @param {string} className Class to be added.
<a name="line226"></a> */
<a name="line227"></a>goog.fx.AbstractDragDrop.prototype.setTargetClass = function(className) {
<a name="line228"></a>  this.targetClass_ = className;
<a name="line229"></a>};
<a name="line230"></a>
<a name="line231"></a>
<a name="line232"></a>/**
<a name="line233"></a> * Whether the control has been initialized.
<a name="line234"></a> *
<a name="line235"></a> * @return {boolean} True if it&#39;s been initialized.
<a name="line236"></a> */
<a name="line237"></a>goog.fx.AbstractDragDrop.prototype.isInitialized = function() {
<a name="line238"></a>  return this.initialized_;
<a name="line239"></a>};
<a name="line240"></a>
<a name="line241"></a>
<a name="line242"></a>/**
<a name="line243"></a> * Add item to drag object.
<a name="line244"></a> *
<a name="line245"></a> * @param {Element|string} element Dom Node, or string representation of node
<a name="line246"></a> *     id, to be used as drag source/drop target.
<a name="line247"></a> * @throws Error Thrown if called on instance of abstract class
<a name="line248"></a> */
<a name="line249"></a>goog.fx.AbstractDragDrop.prototype.addItem = goog.abstractMethod;
<a name="line250"></a>
<a name="line251"></a>
<a name="line252"></a>/**
<a name="line253"></a> * Associate drop target with drag element.
<a name="line254"></a> *
<a name="line255"></a> * @param {goog.fx.AbstractDragDrop} target Target to add.
<a name="line256"></a> */
<a name="line257"></a>goog.fx.AbstractDragDrop.prototype.addTarget = function(target) {
<a name="line258"></a>  this.targets_.push(target);
<a name="line259"></a>  target.isTarget_ = true;
<a name="line260"></a>  this.isSource_ = true;
<a name="line261"></a>};
<a name="line262"></a>
<a name="line263"></a>
<a name="line264"></a>/**
<a name="line265"></a> * Sets the SCROLL event target to make drag element follow scrolling.
<a name="line266"></a> *
<a name="line267"></a> * @param {EventTarget} scrollTarget The element that dispatches SCROLL events.
<a name="line268"></a> */
<a name="line269"></a>goog.fx.AbstractDragDrop.prototype.setScrollTarget = function(scrollTarget) {
<a name="line270"></a>  this.scrollTarget_ = scrollTarget;
<a name="line271"></a>};
<a name="line272"></a>
<a name="line273"></a>
<a name="line274"></a>/**
<a name="line275"></a> * Initialize drag and drop functionality for sources/targets already added.
<a name="line276"></a> * Sources/targets added after init has been called will initialize themselves
<a name="line277"></a> * one by one.
<a name="line278"></a> */
<a name="line279"></a>goog.fx.AbstractDragDrop.prototype.init = function() {
<a name="line280"></a>  if (this.initialized_) {
<a name="line281"></a>    return;
<a name="line282"></a>  }
<a name="line283"></a>  for (var item, i = 0; item = this.items_[i]; i++) {
<a name="line284"></a>    this.initItem(item);
<a name="line285"></a>  }
<a name="line286"></a>
<a name="line287"></a>  this.initialized_ = true;
<a name="line288"></a>};
<a name="line289"></a>
<a name="line290"></a>
<a name="line291"></a>/**
<a name="line292"></a> * Initializes a single item.
<a name="line293"></a> *
<a name="line294"></a> * @param {goog.fx.DragDropItem} item Item to initialize.
<a name="line295"></a> * @protected
<a name="line296"></a> */
<a name="line297"></a>goog.fx.AbstractDragDrop.prototype.initItem = function(item) {
<a name="line298"></a>  if (this.isSource_) {
<a name="line299"></a>    goog.events.listen(item.element, goog.events.EventType.MOUSEDOWN,
<a name="line300"></a>                       item.mouseDown_, false, item);
<a name="line301"></a>    if (this.sourceClass_) {
<a name="line302"></a>      goog.dom.classes.add(item.element, this.sourceClass_);
<a name="line303"></a>    }
<a name="line304"></a>  }
<a name="line305"></a>
<a name="line306"></a>  if (this.isTarget_ &amp;&amp; this.targetClass_) {
<a name="line307"></a>    goog.dom.classes.add(item.element, this.targetClass_);
<a name="line308"></a>  }
<a name="line309"></a>};
<a name="line310"></a>
<a name="line311"></a>
<a name="line312"></a>/**
<a name="line313"></a> * Called when removing an item. Removes event listeners and classes.
<a name="line314"></a> *
<a name="line315"></a> * @param {goog.fx.DragDropItem} item Item to dispose.
<a name="line316"></a> * @protected
<a name="line317"></a> */
<a name="line318"></a>goog.fx.AbstractDragDrop.prototype.disposeItem = function(item) {
<a name="line319"></a>  if (this.isSource_) {
<a name="line320"></a>    goog.events.unlisten(item.element, goog.events.EventType.MOUSEDOWN,
<a name="line321"></a>                         item.mouseDown_, false, item);
<a name="line322"></a>    if (this.sourceClass_) {
<a name="line323"></a>      goog.dom.classes.remove(item.element, this.sourceClass_);
<a name="line324"></a>    }
<a name="line325"></a>  }
<a name="line326"></a>  if (this.isTarget_ &amp;&amp; this.targetClass_) {
<a name="line327"></a>    goog.dom.classes.remove(item.element, this.targetClass_);
<a name="line328"></a>  }
<a name="line329"></a>  item.dispose();
<a name="line330"></a>};
<a name="line331"></a>
<a name="line332"></a>
<a name="line333"></a>/**
<a name="line334"></a> * Removes all items.
<a name="line335"></a> */
<a name="line336"></a>goog.fx.AbstractDragDrop.prototype.removeItems = function() {
<a name="line337"></a>  for (var item, i = 0; item = this.items_[i]; i++) {
<a name="line338"></a>    this.disposeItem(item);
<a name="line339"></a>  }
<a name="line340"></a>  this.items_.length = 0;
<a name="line341"></a>};
<a name="line342"></a>
<a name="line343"></a>
<a name="line344"></a>/**
<a name="line345"></a> * Starts a drag event for an item if the mouse button stays pressed and the
<a name="line346"></a> * cursor moves a few pixels. Allows dragging of items without first having to
<a name="line347"></a> * register them with addItem.
<a name="line348"></a> *
<a name="line349"></a> * @param {goog.events.BrowserEvent} event Mouse down event.
<a name="line350"></a> * @param {goog.fx.DragDropItem} item Item that&#39;s being dragged.
<a name="line351"></a> */
<a name="line352"></a>goog.fx.AbstractDragDrop.prototype.maybeStartDrag = function(event, item) {
<a name="line353"></a>  item.maybeStartDrag_(event, item.element);
<a name="line354"></a>};
<a name="line355"></a>
<a name="line356"></a>
<a name="line357"></a>/**
<a name="line358"></a> * Event handler that&#39;s used to start drag.
<a name="line359"></a> *
<a name="line360"></a> * @param {goog.events.BrowserEvent} event Mouse move event.
<a name="line361"></a> * @param {goog.fx.DragDropItem} item Item that&#39;s being dragged.
<a name="line362"></a> */
<a name="line363"></a>goog.fx.AbstractDragDrop.prototype.startDrag = function(event, item) {
<a name="line364"></a>
<a name="line365"></a>  // Prevent a new drag operation from being started if another one is already
<a name="line366"></a>  // in progress (could happen if the mouse was released outside of the
<a name="line367"></a>  // document).
<a name="line368"></a>  if (this.dragItem_) {
<a name="line369"></a>    return;
<a name="line370"></a>  }
<a name="line371"></a>
<a name="line372"></a>  this.dragItem_ = item;
<a name="line373"></a>
<a name="line374"></a>  // Dispatch DRAGSTART event
<a name="line375"></a>  var dragStartEvent = new goog.fx.DragDropEvent(
<a name="line376"></a>      goog.fx.AbstractDragDrop.EventType.DRAGSTART, this, this.dragItem_);
<a name="line377"></a>  if (this.dispatchEvent(dragStartEvent) == false) {
<a name="line378"></a>    this.dragItem_ = null;
<a name="line379"></a>    return;
<a name="line380"></a>  }
<a name="line381"></a>
<a name="line382"></a>  // Get the source element and create a drag element for it.
<a name="line383"></a>  var el = item.getCurrentDragElement();
<a name="line384"></a>  this.dragEl_ = this.createDragElement(el);
<a name="line385"></a>  var doc = goog.dom.getOwnerDocument(el);
<a name="line386"></a>  doc.body.appendChild(this.dragEl_);
<a name="line387"></a>
<a name="line388"></a>  this.dragger_ = this.createDraggerFor(el, this.dragEl_, event);
<a name="line389"></a>  this.dragger_.setScrollTarget(this.scrollTarget_);
<a name="line390"></a>
<a name="line391"></a>  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG,
<a name="line392"></a>                     this.moveDrag_, false, this);
<a name="line393"></a>
<a name="line394"></a>  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END,
<a name="line395"></a>                     this.endDrag, false, this);
<a name="line396"></a>
<a name="line397"></a>  // IE may issue a &#39;selectstart&#39; event when dragging over an iframe even when
<a name="line398"></a>  // default mousemove behavior is suppressed. If the default selectstart
<a name="line399"></a>  // behavior is not suppressed, elements dragged over will show as selected.
<a name="line400"></a>  goog.events.listen(doc.body, goog.events.EventType.SELECTSTART,
<a name="line401"></a>                     this.suppressSelect_);
<a name="line402"></a>
<a name="line403"></a>  this.recalculateDragTargets();
<a name="line404"></a>  this.recalculateScrollableContainers();
<a name="line405"></a>  this.activeTarget_ = null;
<a name="line406"></a>  this.initScrollableContainerListeners_();
<a name="line407"></a>  this.dragger_.startDrag(event);
<a name="line408"></a>
<a name="line409"></a>  event.preventDefault();
<a name="line410"></a>};
<a name="line411"></a>
<a name="line412"></a>
<a name="line413"></a>/**
<a name="line414"></a> * Recalculates the geometry of this source&#39;s drag targets.  Call this
<a name="line415"></a> * if the position or visibility of a drag target has changed during
<a name="line416"></a> * a drag, or if targets are added or removed.
<a name="line417"></a> *
<a name="line418"></a> * TODO(user): this is an expensive operation;  more efficient APIs
<a name="line419"></a> * may be necessary.
<a name="line420"></a> */
<a name="line421"></a>goog.fx.AbstractDragDrop.prototype.recalculateDragTargets = function() {
<a name="line422"></a>  this.targetList_ = [];
<a name="line423"></a>  for (var target, i = 0; target = this.targets_[i]; i++) {
<a name="line424"></a>    for (var itm, j = 0; itm = target.items_[j]; j++) {
<a name="line425"></a>      this.addDragTarget_(target, itm);
<a name="line426"></a>    }
<a name="line427"></a>  }
<a name="line428"></a>  if (!this.targetBox_) {
<a name="line429"></a>    this.targetBox_ = new goog.math.Box(0, 0, 0, 0);
<a name="line430"></a>  }
<a name="line431"></a>};
<a name="line432"></a>
<a name="line433"></a>
<a name="line434"></a>/**
<a name="line435"></a> * Recalculates the current scroll positions of scrollable containers and
<a name="line436"></a> * allocates targets. Call this if the position of a container changed or if
<a name="line437"></a> * targets are added or removed.
<a name="line438"></a> */
<a name="line439"></a>goog.fx.AbstractDragDrop.prototype.recalculateScrollableContainers =
<a name="line440"></a>    function() {
<a name="line441"></a>  var container, i, j, target;
<a name="line442"></a>  for (i = 0; container = this.scrollableContainers_[i]; i++) {
<a name="line443"></a>    container.containedTargets_ = [];
<a name="line444"></a>    container.savedScrollLeft_ = container.element_.scrollLeft;
<a name="line445"></a>    container.savedScrollTop_ = container.element_.scrollTop;
<a name="line446"></a>    var pos = goog.style.getPageOffset(container.element_);
<a name="line447"></a>    var size = goog.style.getSize(container.element_);
<a name="line448"></a>    container.box_ = new goog.math.Box(pos.y, pos.x + size.width,
<a name="line449"></a>                                       pos.y + size.height, pos.x);
<a name="line450"></a>  }
<a name="line451"></a>
<a name="line452"></a>  for (i = 0; target = this.targetList_[i]; i++) {
<a name="line453"></a>    for (j = 0; container = this.scrollableContainers_[j]; j++) {
<a name="line454"></a>      if (goog.dom.contains(container.element_, target.element_)) {
<a name="line455"></a>        container.containedTargets_.push(target);
<a name="line456"></a>        target.scrollableContainer_ = container;
<a name="line457"></a>      }
<a name="line458"></a>    }
<a name="line459"></a>  }
<a name="line460"></a>};
<a name="line461"></a>
<a name="line462"></a>
<a name="line463"></a>/**
<a name="line464"></a> * Creates the Dragger for the drag element.
<a name="line465"></a> * @param {Element} sourceEl Drag source element.
<a name="line466"></a> * @param {Element} el the element created by createDragElement().
<a name="line467"></a> * @param {goog.events.BrowserEvent} event Mouse down event for start of drag.
<a name="line468"></a> * @return {goog.fx.Dragger} The new Dragger.
<a name="line469"></a> * @protected
<a name="line470"></a> */
<a name="line471"></a>goog.fx.AbstractDragDrop.prototype.createDraggerFor =
<a name="line472"></a>    function(sourceEl, el, event) {
<a name="line473"></a>  // Position the drag element.
<a name="line474"></a>  var pos = this.getDragElementPosition(sourceEl, el, event);
<a name="line475"></a>  el.style.position = &#39;absolute&#39;;
<a name="line476"></a>  el.style.left = pos.x + &#39;px&#39;;
<a name="line477"></a>  el.style.top = pos.y + &#39;px&#39;;
<a name="line478"></a>  return new goog.fx.Dragger(el);
<a name="line479"></a>};
<a name="line480"></a>
<a name="line481"></a>
<a name="line482"></a>/**
<a name="line483"></a> * Event handler that&#39;s used to stop drag. Fires a drop event if over a valid
<a name="line484"></a> * target.
<a name="line485"></a> *
<a name="line486"></a> * @param {goog.fx.DragEvent} event Drag event.
<a name="line487"></a> */
<a name="line488"></a>goog.fx.AbstractDragDrop.prototype.endDrag = function(event) {
<a name="line489"></a>  var activeTarget = event.dragCanceled ? null : this.activeTarget_;
<a name="line490"></a>  if (activeTarget &amp;&amp; activeTarget.target_) {
<a name="line491"></a>    var clientX = event.clientX;
<a name="line492"></a>    var clientY = event.clientY;
<a name="line493"></a>    var scroll = this.getScrollPos();
<a name="line494"></a>    var x = clientX + scroll.x;
<a name="line495"></a>    var y = clientY + scroll.y;
<a name="line496"></a>
<a name="line497"></a>    var subtarget;
<a name="line498"></a>    // If a subtargeting function is enabled get the current subtarget
<a name="line499"></a>    if (this.subtargetFunction_) {
<a name="line500"></a>      subtarget = this.subtargetFunction_(activeTarget.item_,
<a name="line501"></a>          activeTarget.box_, x, y);
<a name="line502"></a>    }
<a name="line503"></a>
<a name="line504"></a>    var dragEvent = new goog.fx.DragDropEvent(
<a name="line505"></a>        goog.fx.AbstractDragDrop.EventType.DRAG, this, this.dragItem_,
<a name="line506"></a>        activeTarget.target_, activeTarget.item_, activeTarget.element_,
<a name="line507"></a>        clientX, clientY, x, y);
<a name="line508"></a>    this.dispatchEvent(dragEvent);
<a name="line509"></a>
<a name="line510"></a>    var dropEvent = new goog.fx.DragDropEvent(
<a name="line511"></a>        goog.fx.AbstractDragDrop.EventType.DROP, this, this.dragItem_,
<a name="line512"></a>        activeTarget.target_, activeTarget.item_, activeTarget.element_,
<a name="line513"></a>        clientX, clientY, x, y, subtarget);
<a name="line514"></a>    activeTarget.target_.dispatchEvent(dropEvent);
<a name="line515"></a>  }
<a name="line516"></a>
<a name="line517"></a>  var dragEndEvent = new goog.fx.DragDropEvent(
<a name="line518"></a>      goog.fx.AbstractDragDrop.EventType.DRAGEND, this, this.dragItem_);
<a name="line519"></a>  this.dispatchEvent(dragEndEvent);
<a name="line520"></a>
<a name="line521"></a>  goog.events.unlisten(this.dragger_, goog.fx.Dragger.EventType.DRAG,
<a name="line522"></a>                       this.moveDrag_, false, this);
<a name="line523"></a>  goog.events.unlisten(this.dragger_, goog.fx.Dragger.EventType.END,
<a name="line524"></a>                       this.endDrag, false, this);
<a name="line525"></a>  var doc = goog.dom.getOwnerDocument(this.dragItem_.getCurrentDragElement());
<a name="line526"></a>  goog.events.unlisten(doc.body, goog.events.EventType.SELECTSTART,
<a name="line527"></a>                       this.suppressSelect_);
<a name="line528"></a>
<a name="line529"></a>
<a name="line530"></a>  this.afterEndDrag(this.activeTarget_ ? this.activeTarget_.item_ : null);
<a name="line531"></a>};
<a name="line532"></a>
<a name="line533"></a>
<a name="line534"></a>/**
<a name="line535"></a> * Called after a drag operation has finished.
<a name="line536"></a> *
<a name="line537"></a> * @param {goog.fx.DragDropItem=} opt_dropTarget Target for successful drop.
<a name="line538"></a> * @protected
<a name="line539"></a> */
<a name="line540"></a>goog.fx.AbstractDragDrop.prototype.afterEndDrag = function(opt_dropTarget) {
<a name="line541"></a>  this.disposeDrag();
<a name="line542"></a>};
<a name="line543"></a>
<a name="line544"></a>
<a name="line545"></a>/**
<a name="line546"></a> * Called once a drag operation has finished. Removes event listeners and
<a name="line547"></a> * elements.
<a name="line548"></a> *
<a name="line549"></a> * @protected
<a name="line550"></a> */
<a name="line551"></a>goog.fx.AbstractDragDrop.prototype.disposeDrag = function() {
<a name="line552"></a>  this.disposeScrollableContainerListeners_();
<a name="line553"></a>  this.dragger_.dispose();
<a name="line554"></a>
<a name="line555"></a>  goog.dom.removeNode(this.dragEl_);
<a name="line556"></a>  delete this.dragItem_;
<a name="line557"></a>  delete this.dragEl_;
<a name="line558"></a>  delete this.dragger_;
<a name="line559"></a>  delete this.targetList_;
<a name="line560"></a>  delete this.activeTarget_;
<a name="line561"></a>};
<a name="line562"></a>
<a name="line563"></a>
<a name="line564"></a>/**
<a name="line565"></a> * Event handler for drag events. Determines the active drop target, if any, and
<a name="line566"></a> * fires dragover and dragout events appropriately.
<a name="line567"></a> *
<a name="line568"></a> * @param {goog.fx.DragEvent} event Drag event.
<a name="line569"></a> * @private
<a name="line570"></a> */
<a name="line571"></a>goog.fx.AbstractDragDrop.prototype.moveDrag_ = function(event) {
<a name="line572"></a>  var position = this.getEventPosition(event);
<a name="line573"></a>  var x = position.x;
<a name="line574"></a>  var y = position.y;
<a name="line575"></a>
<a name="line576"></a>  // Check if we&#39;re still inside the bounds of the active target, if not fire
<a name="line577"></a>  // a dragout event and proceed to find a new target.
<a name="line578"></a>  var activeTarget = this.activeTarget_;
<a name="line579"></a>
<a name="line580"></a>  var subtarget;
<a name="line581"></a>  if (activeTarget) {
<a name="line582"></a>    // If a subtargeting function is enabled get the current subtarget
<a name="line583"></a>    if (this.subtargetFunction_ &amp;&amp; activeTarget.target_) {
<a name="line584"></a>      subtarget = this.subtargetFunction_(activeTarget.item_,
<a name="line585"></a>          activeTarget.box_, x, y);
<a name="line586"></a>    }
<a name="line587"></a>
<a name="line588"></a>    if (activeTarget.box_.contains(position) &amp;&amp;
<a name="line589"></a>        subtarget == this.activeSubtarget_) {
<a name="line590"></a>      return;
<a name="line591"></a>    }
<a name="line592"></a>
<a name="line593"></a>    if (activeTarget.target_) {
<a name="line594"></a>      var sourceDragOutEvent = new goog.fx.DragDropEvent(
<a name="line595"></a>          goog.fx.AbstractDragDrop.EventType.DRAGOUT, this, this.dragItem_,
<a name="line596"></a>          activeTarget.target_, activeTarget.item_, activeTarget.element_);
<a name="line597"></a>      this.dispatchEvent(sourceDragOutEvent);
<a name="line598"></a>
<a name="line599"></a>      // The event should be dispatched the by target DragDrop so that the
<a name="line600"></a>      // target DragDrop can manage these events without having to know what
<a name="line601"></a>      // sources this is a target for.
<a name="line602"></a>      var targetDragOutEvent = new goog.fx.DragDropEvent(
<a name="line603"></a>          goog.fx.AbstractDragDrop.EventType.DRAGOUT,
<a name="line604"></a>          this,
<a name="line605"></a>          this.dragItem_,
<a name="line606"></a>          activeTarget.target_,
<a name="line607"></a>          activeTarget.item_,
<a name="line608"></a>          activeTarget.element_,
<a name="line609"></a>          undefined,
<a name="line610"></a>          undefined,
<a name="line611"></a>          undefined,
<a name="line612"></a>          undefined,
<a name="line613"></a>          this.activeSubtarget_);
<a name="line614"></a>      activeTarget.target_.dispatchEvent(targetDragOutEvent);
<a name="line615"></a>    }
<a name="line616"></a>    this.activeSubtarget_ = subtarget;
<a name="line617"></a>    this.activeTarget_ = null;
<a name="line618"></a>  }
<a name="line619"></a>
<a name="line620"></a>  // Check if inside target box
<a name="line621"></a>  if (this.targetBox_.contains(position)) {
<a name="line622"></a>    // Search for target and fire a dragover event if found
<a name="line623"></a>    activeTarget = this.activeTarget_ = this.getTargetFromPosition_(position);
<a name="line624"></a>    if (activeTarget &amp;&amp; activeTarget.target_) {
<a name="line625"></a>      // If a subtargeting function is enabled get the current subtarget
<a name="line626"></a>      if (this.subtargetFunction_) {
<a name="line627"></a>        subtarget = this.subtargetFunction_(activeTarget.item_,
<a name="line628"></a>            activeTarget.box_, x, y);
<a name="line629"></a>      }
<a name="line630"></a>      var sourceDragOverEvent = new goog.fx.DragDropEvent(
<a name="line631"></a>          goog.fx.AbstractDragDrop.EventType.DRAGOVER, this, this.dragItem_,
<a name="line632"></a>          activeTarget.target_, activeTarget.item_, activeTarget.element_);
<a name="line633"></a>      sourceDragOverEvent.subtarget = subtarget;
<a name="line634"></a>      this.dispatchEvent(sourceDragOverEvent);
<a name="line635"></a>
<a name="line636"></a>      // The event should be dispatched by the target DragDrop so that the
<a name="line637"></a>      // target DragDrop can manage these events without having to know what
<a name="line638"></a>      // sources this is a target for.
<a name="line639"></a>      var targetDragOverEvent = new goog.fx.DragDropEvent(
<a name="line640"></a>          goog.fx.AbstractDragDrop.EventType.DRAGOVER, this, this.dragItem_,
<a name="line641"></a>          activeTarget.target_, activeTarget.item_, activeTarget.element_,
<a name="line642"></a>          event.clientX, event.clientY, undefined, undefined, subtarget);
<a name="line643"></a>      activeTarget.target_.dispatchEvent(targetDragOverEvent);
<a name="line644"></a>
<a name="line645"></a>    } else if (!activeTarget) {
<a name="line646"></a>      // If no target was found create a dummy one so we won&#39;t have to iterate
<a name="line647"></a>      // over all possible targets for every move event.
<a name="line648"></a>      this.activeTarget_ = this.maybeCreateDummyTargetForPosition_(x, y);
<a name="line649"></a>    }
<a name="line650"></a>  }
<a name="line651"></a>};
<a name="line652"></a>
<a name="line653"></a>
<a name="line654"></a>/**
<a name="line655"></a> * Event handler for suppressing selectstart events. Selecting should be
<a name="line656"></a> * disabled while dragging.
<a name="line657"></a> *
<a name="line658"></a> * @param {goog.events.Event} event The selectstart event to suppress.
<a name="line659"></a> * @return {boolean} Whether to perform default behavior.
<a name="line660"></a> * @private
<a name="line661"></a> */
<a name="line662"></a>goog.fx.AbstractDragDrop.prototype.suppressSelect_ = function(event) {
<a name="line663"></a>  return false;
<a name="line664"></a>};
<a name="line665"></a>
<a name="line666"></a>
<a name="line667"></a>/**
<a name="line668"></a> * Sets up listeners for the scrollable containers that keep track of their
<a name="line669"></a> * scroll positions.
<a name="line670"></a> * @private
<a name="line671"></a> */
<a name="line672"></a>goog.fx.AbstractDragDrop.prototype.initScrollableContainerListeners_ =
<a name="line673"></a>    function() {
<a name="line674"></a>  var container, i;
<a name="line675"></a>  for (i = 0; container = this.scrollableContainers_[i]; i++) {
<a name="line676"></a>    goog.events.listen(container.element_, goog.events.EventType.SCROLL,
<a name="line677"></a>        this.containerScrollHandler_, false, this);
<a name="line678"></a>  }
<a name="line679"></a>};
<a name="line680"></a>
<a name="line681"></a>
<a name="line682"></a>/**
<a name="line683"></a> * Cleans up the scrollable container listeners.
<a name="line684"></a> * @private
<a name="line685"></a> */
<a name="line686"></a>goog.fx.AbstractDragDrop.prototype.disposeScrollableContainerListeners_ =
<a name="line687"></a>    function() {
<a name="line688"></a>  for (var i = 0, container; container = this.scrollableContainers_[i]; i++) {
<a name="line689"></a>    goog.events.unlisten(container.element_, &#39;scroll&#39;,
<a name="line690"></a>        this.containerScrollHandler_, false, this);
<a name="line691"></a>    container.containedTargets_ = [];
<a name="line692"></a>  }
<a name="line693"></a>};
<a name="line694"></a>
<a name="line695"></a>
<a name="line696"></a>/**
<a name="line697"></a> * Makes drag and drop aware of a target container that could scroll mid drag.
<a name="line698"></a> * @param {Element} element The scroll container.
<a name="line699"></a> */
<a name="line700"></a>goog.fx.AbstractDragDrop.prototype.addScrollableContainer = function(element) {
<a name="line701"></a>  this.scrollableContainers_.push(new goog.fx.ScrollableContainer_(element));
<a name="line702"></a>};
<a name="line703"></a>
<a name="line704"></a>
<a name="line705"></a>/**
<a name="line706"></a> * Removes all scrollable containers.
<a name="line707"></a> */
<a name="line708"></a>goog.fx.AbstractDragDrop.prototype.removeAllScrollableContainers = function() {
<a name="line709"></a>  this.disposeScrollableContainerListeners_();
<a name="line710"></a>  this.scrollableContainers_ = [];
<a name="line711"></a>};
<a name="line712"></a>
<a name="line713"></a>
<a name="line714"></a>/**
<a name="line715"></a> * Event handler for containers scrolling.
<a name="line716"></a> * @param {goog.events.Event} e The event.
<a name="line717"></a> * @private
<a name="line718"></a> */
<a name="line719"></a>goog.fx.AbstractDragDrop.prototype.containerScrollHandler_ = function(e) {
<a name="line720"></a>  for (var i = 0, container; container = this.scrollableContainers_[i]; i++) {
<a name="line721"></a>    if (e.target == container.element_) {
<a name="line722"></a>      var deltaTop = container.savedScrollTop_ - container.element_.scrollTop;
<a name="line723"></a>      var deltaLeft =
<a name="line724"></a>          container.savedScrollLeft_ - container.element_.scrollLeft;
<a name="line725"></a>      container.savedScrollTop_ = container.element_.scrollTop;
<a name="line726"></a>      container.savedScrollLeft_ = container.element_.scrollLeft;
<a name="line727"></a>
<a name="line728"></a>      // When the container scrolls, it&#39;s possible that one of the targets will
<a name="line729"></a>      // move to the region contained by the dummy target. Since we don&#39;t know
<a name="line730"></a>      // which sides (if any) of the dummy target are defined by targets
<a name="line731"></a>      // contained by this container, we are conservative and just shrink it.
<a name="line732"></a>      if (this.dummyTarget_ &amp;&amp; this.activeTarget_ == this.dummyTarget_) {
<a name="line733"></a>        if (deltaTop &gt; 0) {
<a name="line734"></a>          this.dummyTarget_.box_.top += deltaTop;
<a name="line735"></a>        } else {
<a name="line736"></a>          this.dummyTarget_.box_.bottom += deltaTop;
<a name="line737"></a>        }
<a name="line738"></a>        if (deltaLeft &gt; 0) {
<a name="line739"></a>          this.dummyTarget_.box_.left += deltaLeft;
<a name="line740"></a>        } else {
<a name="line741"></a>          this.dummyTarget_.box_.right += deltaLeft;
<a name="line742"></a>        }
<a name="line743"></a>      }
<a name="line744"></a>      for (var j = 0, target; target = container.containedTargets_[j]; j++) {
<a name="line745"></a>        var box = target.box_;
<a name="line746"></a>        box.top += deltaTop;
<a name="line747"></a>        box.left += deltaLeft;
<a name="line748"></a>        box.bottom += deltaTop;
<a name="line749"></a>        box.right += deltaLeft;
<a name="line750"></a>
<a name="line751"></a>        this.calculateTargetBox_(box);
<a name="line752"></a>      }
<a name="line753"></a>    }
<a name="line754"></a>  }
<a name="line755"></a>  this.dragger_.onScroll_(e);
<a name="line756"></a>};
<a name="line757"></a>
<a name="line758"></a>
<a name="line759"></a>/**
<a name="line760"></a> * Set a function that provides subtargets. A subtargeting function
<a name="line761"></a> * returns an arbitrary identifier for each subtarget of an element.
<a name="line762"></a> * DnD code will generate additional drag over / out events when
<a name="line763"></a> * switching from subtarget to subtarget. This is useful for instance
<a name="line764"></a> * if you are interested if you are on the top half or the bottom half
<a name="line765"></a> * of the element.
<a name="line766"></a> * The provided function will be given the DragDropItem, box, x, y
<a name="line767"></a> * box is the current window coordinates occupied by element
<a name="line768"></a> * x, y is the mouse position in window coordinates
<a name="line769"></a> *
<a name="line770"></a> * @param {Function} f The new subtarget function.
<a name="line771"></a> */
<a name="line772"></a>goog.fx.AbstractDragDrop.prototype.setSubtargetFunction = function(f) {
<a name="line773"></a>  this.subtargetFunction_ = f;
<a name="line774"></a>};
<a name="line775"></a>
<a name="line776"></a>
<a name="line777"></a>/**
<a name="line778"></a> * Creates an element for the item being dragged.
<a name="line779"></a> *
<a name="line780"></a> * @param {Element} sourceEl Drag source element.
<a name="line781"></a> * @return {Element} The new drag element.
<a name="line782"></a> */
<a name="line783"></a>goog.fx.AbstractDragDrop.prototype.createDragElement = function(sourceEl) {
<a name="line784"></a>  var dragEl = this.cloneNode_(sourceEl);
<a name="line785"></a>  if (this.dragClass_) {
<a name="line786"></a>    goog.dom.classes.add(dragEl, this.dragClass_);
<a name="line787"></a>  }
<a name="line788"></a>
<a name="line789"></a>  return dragEl;
<a name="line790"></a>};
<a name="line791"></a>
<a name="line792"></a>
<a name="line793"></a>/**
<a name="line794"></a> * Returns the position for the drag element.
<a name="line795"></a> *
<a name="line796"></a> * @param {Element} el Drag source element.
<a name="line797"></a> * @param {Element} dragEl The dragged element created by createDragElement().
<a name="line798"></a> * @param {goog.events.BrowserEvent} event Mouse down event for start of drag.
<a name="line799"></a> * @return {goog.math.Coordinate} The position for the drag element.
<a name="line800"></a> */
<a name="line801"></a>goog.fx.AbstractDragDrop.prototype.getDragElementPosition =
<a name="line802"></a>    function(el, dragEl, event) {
<a name="line803"></a>  var pos = goog.style.getPageOffset(el);
<a name="line804"></a>
<a name="line805"></a>  // Subtract margin from drag element position twice, once to adjust the
<a name="line806"></a>  // position given by the original node and once for the drag node.
<a name="line807"></a>  var marginBox = goog.style.getMarginBox(el);
<a name="line808"></a>  pos.x -= (marginBox.left || 0) * 2;
<a name="line809"></a>  pos.y -= (marginBox.top || 0) * 2;
<a name="line810"></a>
<a name="line811"></a>  return pos;
<a name="line812"></a>};
<a name="line813"></a>
<a name="line814"></a>
<a name="line815"></a>/**
<a name="line816"></a> * Returns the dragger object.
<a name="line817"></a> *
<a name="line818"></a> * @return {goog.fx.Dragger} The dragger object used by this drag and drop
<a name="line819"></a> *     instance.
<a name="line820"></a> */
<a name="line821"></a>goog.fx.AbstractDragDrop.prototype.getDragger = function() {
<a name="line822"></a>  return this.dragger_;
<a name="line823"></a>};
<a name="line824"></a>
<a name="line825"></a>
<a name="line826"></a>/**
<a name="line827"></a> * Creates copy of node being dragged.
<a name="line828"></a> *
<a name="line829"></a> * @param {Element} sourceEl Element to copy.
<a name="line830"></a> * @return {Element} The clone of {@code sourceEl}.
<a name="line831"></a> * @private
<a name="line832"></a> */
<a name="line833"></a>goog.fx.AbstractDragDrop.prototype.cloneNode_ = function(sourceEl) {
<a name="line834"></a>  var clonedEl = /** @type {Element} */ (sourceEl.cloneNode(true));
<a name="line835"></a>  switch (sourceEl.tagName.toLowerCase()) {
<a name="line836"></a>    case &#39;tr&#39;:
<a name="line837"></a>      return goog.dom.createDom(
<a name="line838"></a>          &#39;table&#39;, null, goog.dom.createDom(&#39;tbody&#39;, null, clonedEl));
<a name="line839"></a>    case &#39;td&#39;:
<a name="line840"></a>    case &#39;th&#39;:
<a name="line841"></a>      return goog.dom.createDom(
<a name="line842"></a>          &#39;table&#39;, null, goog.dom.createDom(&#39;tbody&#39;, null, goog.dom.createDom(
<a name="line843"></a>          &#39;tr&#39;, null, clonedEl)));
<a name="line844"></a>    default:
<a name="line845"></a>      return clonedEl;
<a name="line846"></a>  }
<a name="line847"></a>};
<a name="line848"></a>
<a name="line849"></a>
<a name="line850"></a>/**
<a name="line851"></a> * Add possible drop target for current drag operation.
<a name="line852"></a> *
<a name="line853"></a> * @param {goog.fx.AbstractDragDrop} target Drag handler.
<a name="line854"></a> * @param {goog.fx.DragDropItem} item Item that&#39;s being dragged.
<a name="line855"></a> * @private
<a name="line856"></a> */
<a name="line857"></a>goog.fx.AbstractDragDrop.prototype.addDragTarget_ = function(target, item) {
<a name="line858"></a>
<a name="line859"></a>  // Get all the draggable elements and add each one.
<a name="line860"></a>  var draggableElements = item.getDraggableElements();
<a name="line861"></a>  var targetList = this.targetList_;
<a name="line862"></a>  for (var i = 0; i &lt; draggableElements.length; i++) {
<a name="line863"></a>    var draggableElement = draggableElements[i];
<a name="line864"></a>
<a name="line865"></a>    // Determine target position and dimension
<a name="line866"></a>    var pos = goog.style.getPageOffset(draggableElement);
<a name="line867"></a>    var size = goog.style.getSize(draggableElement);
<a name="line868"></a>
<a name="line869"></a>    var box = new goog.math.Box(pos.y, pos.x + size.width,
<a name="line870"></a>                                pos.y + size.height, pos.x);
<a name="line871"></a>
<a name="line872"></a>    targetList.push(
<a name="line873"></a>        new goog.fx.ActiveDropTarget_(box, target, item, draggableElement));
<a name="line874"></a>
<a name="line875"></a>    this.calculateTargetBox_(box);
<a name="line876"></a>  }
<a name="line877"></a>};
<a name="line878"></a>
<a name="line879"></a>
<a name="line880"></a>/**
<a name="line881"></a> * Calculate the outer bounds (the region all targets are inside).
<a name="line882"></a> *
<a name="line883"></a> * @param {goog.math.Box} box Box describing the position and dimension
<a name="line884"></a> *     of a drag target.
<a name="line885"></a> * @private
<a name="line886"></a> */
<a name="line887"></a>goog.fx.AbstractDragDrop.prototype.calculateTargetBox_ = function(box) {
<a name="line888"></a>  if (this.targetList_.length == 1) {
<a name="line889"></a>    this.targetBox_ = new goog.math.Box(box.top, box.right,
<a name="line890"></a>                                        box.bottom, box.left);
<a name="line891"></a>  } else {
<a name="line892"></a>    var tb = this.targetBox_;
<a name="line893"></a>    tb.left = Math.min(box.left, tb.left);
<a name="line894"></a>    tb.right = Math.max(box.right, tb.right);
<a name="line895"></a>    tb.top = Math.min(box.top, tb.top);
<a name="line896"></a>    tb.bottom = Math.max(box.bottom, tb.bottom);
<a name="line897"></a>  }
<a name="line898"></a>};
<a name="line899"></a>
<a name="line900"></a>
<a name="line901"></a>/**
<a name="line902"></a> * Creates a dummy target for the given cursor position. The assumption is to
<a name="line903"></a> * create as big dummy target box as possible, the only constraints are:
<a name="line904"></a> * - The dummy target box cannot overlap any of real target boxes.
<a name="line905"></a> * - The dummy target has to contain a point with current mouse coordinates.
<a name="line906"></a> *
<a name="line907"></a> * NOTE: For performance reasons the box construction algorithm is kept simple
<a name="line908"></a> * and it is not optimal (see example below). Currently it is O(n) in regard to
<a name="line909"></a> * the number of real drop target boxes, but its result depends on the order
<a name="line910"></a> * of those boxes being processed (the order in which they&#39;re added to the
<a name="line911"></a> * targetList_ collection).
<a name="line912"></a> *
<a name="line913"></a> * The algorithm.
<a name="line914"></a> * a) Assumptions
<a name="line915"></a> * - Mouse pointer is in the bounding box of real target boxes.
<a name="line916"></a> * - None of the boxes have negative coordinate values.
<a name="line917"></a> * - Mouse pointer is not contained by any of &quot;real target&quot; boxes.
<a name="line918"></a> * - For targets inside a scrollable container, the box used is the
<a name="line919"></a> *   intersection of the scrollable container&#39;s box and the target&#39;s box.
<a name="line920"></a> *   This is because the part of the target that extends outside the scrollable
<a name="line921"></a> *   container should not be used in the clipping calculations.
<a name="line922"></a> *
<a name="line923"></a> * b) Outline
<a name="line924"></a> * - Initialize the fake target to the bounding box of real targets.
<a name="line925"></a> * - For each real target box - clip the fake target box so it does not contain
<a name="line926"></a> *   that target box, but does contain the mouse pointer.
<a name="line927"></a> *   -- Project the real target box, mouse pointer and fake target box onto
<a name="line928"></a> *      both axes and calculate the clipping coordinates.
<a name="line929"></a> *   -- Only one coordinate is used to clip the fake target box to keep the
<a name="line930"></a> *      fake target as big as possible.
<a name="line931"></a> *   -- If the projection of the real target box contains the mouse pointer,
<a name="line932"></a> *      clipping for a given axis is not possible.
<a name="line933"></a> *   -- If both clippings are possible, the clipping more distant from the
<a name="line934"></a> *      mouse pointer is selected to keep bigger fake target area.
<a name="line935"></a> * - Save the created fake target only if it has a big enough area.
<a name="line936"></a> *
<a name="line937"></a> *
<a name="line938"></a> * c) Example
<a name="line939"></a> * &lt;pre&gt;
<a name="line940"></a> *        Input:           Algorithm created box:        Maximum box:
<a name="line941"></a> * +---------------------+ +---------------------+ +---------------------+
<a name="line942"></a> * | B1      |        B2 | | B1               B2 | | B1               B2 |
<a name="line943"></a> * |         |           | |   +-------------+   | |+-------------------+|
<a name="line944"></a> * |---------x-----------| |   |             |   | ||                   ||
<a name="line945"></a> * |         |           | |   |             |   | ||                   ||
<a name="line946"></a> * |         |           | |   |             |   | ||                   ||
<a name="line947"></a> * |         |           | |   |             |   | ||                   ||
<a name="line948"></a> * |         |           | |   |             |   | ||                   ||
<a name="line949"></a> * |         |           | |   +-------------+   | |+-------------------+|
<a name="line950"></a> * | B4      |        B3 | | B4               B3 | | B4               B3 |
<a name="line951"></a> * +---------------------+ +---------------------+ +---------------------+
<a name="line952"></a> * &lt;/pre&gt;
<a name="line953"></a> *
<a name="line954"></a> * @param {number} x Cursor position on the x-axis.
<a name="line955"></a> * @param {number} y Cursor position on the y-axis.
<a name="line956"></a> * @return {goog.fx.ActiveDropTarget_} Dummy drop target.
<a name="line957"></a> * @private
<a name="line958"></a> */
<a name="line959"></a>goog.fx.AbstractDragDrop.prototype.maybeCreateDummyTargetForPosition_ =
<a name="line960"></a>    function(x, y) {
<a name="line961"></a>  if (!this.dummyTarget_) {
<a name="line962"></a>    this.dummyTarget_ = new goog.fx.ActiveDropTarget_(this.targetBox_.clone());
<a name="line963"></a>  }
<a name="line964"></a>  var fakeTargetBox = this.dummyTarget_.box_;
<a name="line965"></a>
<a name="line966"></a>  // Initialize the fake target box to the bounding box of DnD targets.
<a name="line967"></a>  fakeTargetBox.top = this.targetBox_.top;
<a name="line968"></a>  fakeTargetBox.right = this.targetBox_.right;
<a name="line969"></a>  fakeTargetBox.bottom = this.targetBox_.bottom;
<a name="line970"></a>  fakeTargetBox.left = this.targetBox_.left;
<a name="line971"></a>
<a name="line972"></a>  // Clip the fake target based on mouse position and DnD target boxes.
<a name="line973"></a>  for (var i = 0, target; target = this.targetList_[i]; i++) {
<a name="line974"></a>    var box = target.box_;
<a name="line975"></a>
<a name="line976"></a>    if (target.scrollableContainer_) {
<a name="line977"></a>      // If the target has a scrollable container, use the intersection of that
<a name="line978"></a>      // container&#39;s box and the target&#39;s box.
<a name="line979"></a>      var scrollBox = target.scrollableContainer_.box_;
<a name="line980"></a>
<a name="line981"></a>      box = new goog.math.Box(
<a name="line982"></a>          Math.max(box.top, scrollBox.top),
<a name="line983"></a>          Math.min(box.right, scrollBox.right),
<a name="line984"></a>          Math.min(box.bottom, scrollBox.bottom),
<a name="line985"></a>          Math.max(box.left, scrollBox.left));
<a name="line986"></a>    }
<a name="line987"></a>
<a name="line988"></a>    // Calculate clipping coordinates for horizontal and vertical axis.
<a name="line989"></a>    // The clipping coordinate is calculated by projecting fake target box,
<a name="line990"></a>    // the mouse pointer and DnD target box onto an axis and checking how
<a name="line991"></a>    // box projections overlap and if the projected DnD target box contains
<a name="line992"></a>    // mouse pointer. The clipping coordinate cannot be computed and is set to
<a name="line993"></a>    // a negative value if the projected DnD target contains the mouse pointer.
<a name="line994"></a>
<a name="line995"></a>    var horizontalClip = null; // Assume mouse is above or below the DnD box.
<a name="line996"></a>    if (x &gt;= box.right) { // Mouse is to the right of the DnD box.
<a name="line997"></a>      // Clip the fake box only if the DnD box overlaps it.
<a name="line998"></a>      horizontalClip = box.right &gt; fakeTargetBox.left ?
<a name="line999"></a>          box.right : fakeTargetBox.left;
<a name="line1000"></a>    } else if (x &lt; box.left) { // Mouse is to the left of the DnD box.
<a name="line1001"></a>      // Clip the fake box only if the DnD box overlaps it.
<a name="line1002"></a>      horizontalClip = box.left &lt; fakeTargetBox.right ?
<a name="line1003"></a>          box.left : fakeTargetBox.right;
<a name="line1004"></a>    }
<a name="line1005"></a>    var verticalClip = null;
<a name="line1006"></a>    if (y &gt;= box.bottom) {
<a name="line1007"></a>      verticalClip = box.bottom &gt; fakeTargetBox.top ?
<a name="line1008"></a>          box.bottom : fakeTargetBox.top;
<a name="line1009"></a>    } else if (y &lt; box.top) {
<a name="line1010"></a>      verticalClip = box.top &lt; fakeTargetBox.bottom ?
<a name="line1011"></a>          box.top : fakeTargetBox.bottom;
<a name="line1012"></a>    }
<a name="line1013"></a>
<a name="line1014"></a>    // If both clippings are possible, choose one that gives us larger distance
<a name="line1015"></a>    // to mouse pointer (mark the shorter clipping as impossible, by setting it
<a name="line1016"></a>    // to null).
<a name="line1017"></a>    if (!goog.isNull(horizontalClip) &amp;&amp; !goog.isNull(verticalClip)) {
<a name="line1018"></a>      if (Math.abs(horizontalClip - x) &gt; Math.abs(verticalClip - y)) {
<a name="line1019"></a>        verticalClip = null;
<a name="line1020"></a>      } else {
<a name="line1021"></a>        horizontalClip = null;
<a name="line1022"></a>      }
<a name="line1023"></a>    }
<a name="line1024"></a>
<a name="line1025"></a>    // Clip none or one of fake target box sides (at most one clipping
<a name="line1026"></a>    // coordinate can be active).
<a name="line1027"></a>    if (!goog.isNull(horizontalClip)) {
<a name="line1028"></a>      if (horizontalClip &lt;= x) {
<a name="line1029"></a>        fakeTargetBox.left = horizontalClip;
<a name="line1030"></a>      } else {
<a name="line1031"></a>        fakeTargetBox.right = horizontalClip;
<a name="line1032"></a>      }
<a name="line1033"></a>    } else if (!goog.isNull(verticalClip)) {
<a name="line1034"></a>      if (verticalClip &lt;= y) {
<a name="line1035"></a>        fakeTargetBox.top = verticalClip;
<a name="line1036"></a>      } else {
<a name="line1037"></a>        fakeTargetBox.bottom = verticalClip;
<a name="line1038"></a>      }
<a name="line1039"></a>    }
<a name="line1040"></a>  }
<a name="line1041"></a>
<a name="line1042"></a>  // Only return the new fake target if it is big enough.
<a name="line1043"></a>  return (fakeTargetBox.right - fakeTargetBox.left) *
<a name="line1044"></a>         (fakeTargetBox.bottom - fakeTargetBox.top) &gt;=
<a name="line1045"></a>         goog.fx.AbstractDragDrop.DUMMY_TARGET_MIN_SIZE_ ?
<a name="line1046"></a>      this.dummyTarget_ : null;
<a name="line1047"></a>};
<a name="line1048"></a>
<a name="line1049"></a>
<a name="line1050"></a>/**
<a name="line1051"></a> * Returns the target for a given cursor position.
<a name="line1052"></a> *
<a name="line1053"></a> * @param {goog.math.Coordinate} position Cursor position.
<a name="line1054"></a> * @return {Object} Target for position or null if no target was defined
<a name="line1055"></a> *     for the given position.
<a name="line1056"></a> * @private
<a name="line1057"></a> */
<a name="line1058"></a>goog.fx.AbstractDragDrop.prototype.getTargetFromPosition_ = function(position) {
<a name="line1059"></a>  for (var target, i = 0; target = this.targetList_[i]; i++) {
<a name="line1060"></a>    if (target.box_.contains(position)) {
<a name="line1061"></a>      if (target.scrollableContainer_) {
<a name="line1062"></a>        // If we have a scrollable container we will need to make sure
<a name="line1063"></a>        // we account for clipping of the scroll area
<a name="line1064"></a>        var box = target.scrollableContainer_.box_;
<a name="line1065"></a>        if (box.contains(position)) {
<a name="line1066"></a>          return target;
<a name="line1067"></a>        }
<a name="line1068"></a>      } else {
<a name="line1069"></a>        return target;
<a name="line1070"></a>      }
<a name="line1071"></a>    }
<a name="line1072"></a>  }
<a name="line1073"></a>
<a name="line1074"></a>  return null;
<a name="line1075"></a>};
<a name="line1076"></a>
<a name="line1077"></a>
<a name="line1078"></a>/**
<a name="line1079"></a> * Checks whatever a given point is inside a given box.
<a name="line1080"></a> *
<a name="line1081"></a> * @param {number} x Cursor position on the x-axis.
<a name="line1082"></a> * @param {number} y Cursor position on the y-axis.
<a name="line1083"></a> * @param {goog.math.Box} box Box to check position against.
<a name="line1084"></a> * @return {boolean} Whether the given point is inside {@code box}.
<a name="line1085"></a> * @protected
<a name="line1086"></a> * @deprecated Use goog.math.Box.contains.
<a name="line1087"></a> */
<a name="line1088"></a>goog.fx.AbstractDragDrop.prototype.isInside = function(x, y, box) {
<a name="line1089"></a>  return x &gt;= box.left &amp;&amp;
<a name="line1090"></a>         x &lt; box.right &amp;&amp;
<a name="line1091"></a>         y &gt;= box.top &amp;&amp;
<a name="line1092"></a>         y &lt; box.bottom;
<a name="line1093"></a>};
<a name="line1094"></a>
<a name="line1095"></a>
<a name="line1096"></a>/**
<a name="line1097"></a> * Gets the scroll distance as a coordinate object, using
<a name="line1098"></a> * the window of the current drag element&#39;s dom.
<a name="line1099"></a> * @return {goog.math.Coordinate} Object with scroll offsets &#39;x&#39; and &#39;y&#39;.
<a name="line1100"></a> * @protected
<a name="line1101"></a> */
<a name="line1102"></a>goog.fx.AbstractDragDrop.prototype.getScrollPos = function() {
<a name="line1103"></a>  return goog.dom.getDomHelper(this.dragEl_).getDocumentScroll();
<a name="line1104"></a>};
<a name="line1105"></a>
<a name="line1106"></a>
<a name="line1107"></a>/**
<a name="line1108"></a> * Get the position of a drag event.
<a name="line1109"></a> * @param {goog.fx.DragEvent} event Drag event.
<a name="line1110"></a> * @return {goog.math.Coordinate} Position of the event.
<a name="line1111"></a> * @protected
<a name="line1112"></a> */
<a name="line1113"></a>goog.fx.AbstractDragDrop.prototype.getEventPosition = function(event) {
<a name="line1114"></a>  var scroll = this.getScrollPos();
<a name="line1115"></a>  return new goog.math.Coordinate(event.clientX + scroll.x,
<a name="line1116"></a>                                  event.clientY + scroll.y);
<a name="line1117"></a>};
<a name="line1118"></a>
<a name="line1119"></a>
<a name="line1120"></a>/** @override */
<a name="line1121"></a>goog.fx.AbstractDragDrop.prototype.disposeInternal = function() {
<a name="line1122"></a>  goog.base(this, &#39;disposeInternal&#39;);
<a name="line1123"></a>  this.removeItems();
<a name="line1124"></a>};
<a name="line1125"></a>
<a name="line1126"></a>
<a name="line1127"></a>
<a name="line1128"></a>/**
<a name="line1129"></a> * Object representing a drag and drop event.
<a name="line1130"></a> *
<a name="line1131"></a> * @param {string} type Event type.
<a name="line1132"></a> * @param {goog.fx.AbstractDragDrop} source Source drag drop object.
<a name="line1133"></a> * @param {goog.fx.DragDropItem} sourceItem Source item.
<a name="line1134"></a> * @param {goog.fx.AbstractDragDrop=} opt_target Target drag drop object.
<a name="line1135"></a> * @param {goog.fx.DragDropItem=} opt_targetItem Target item.
<a name="line1136"></a> * @param {Element=} opt_targetElement Target element.
<a name="line1137"></a> * @param {number=} opt_clientX X-Position relative to the screen.
<a name="line1138"></a> * @param {number=} opt_clientY Y-Position relative to the screen.
<a name="line1139"></a> * @param {number=} opt_x X-Position relative to the viewport.
<a name="line1140"></a> * @param {number=} opt_y Y-Position relative to the viewport.
<a name="line1141"></a> * @param {Object=} opt_subtarget The currently active subtarget.
<a name="line1142"></a> * @extends {goog.events.Event}
<a name="line1143"></a> * @constructor
<a name="line1144"></a> */
<a name="line1145"></a>goog.fx.DragDropEvent = function(type, source, sourceItem,
<a name="line1146"></a>                                 opt_target, opt_targetItem, opt_targetElement,
<a name="line1147"></a>                                 opt_clientX, opt_clientY, opt_x, opt_y,
<a name="line1148"></a>                                 opt_subtarget) {
<a name="line1149"></a>  // TODO(eae): Get rid of all the optional parameters and have the caller set
<a name="line1150"></a>  // the fields directly instead.
<a name="line1151"></a>  goog.base(this, type);
<a name="line1152"></a>
<a name="line1153"></a>  /**
<a name="line1154"></a>   * Reference to the source goog.fx.AbstractDragDrop object.
<a name="line1155"></a>   * @type {goog.fx.AbstractDragDrop}
<a name="line1156"></a>   */
<a name="line1157"></a>  this.dragSource = source;
<a name="line1158"></a>
<a name="line1159"></a>  /**
<a name="line1160"></a>   * Reference to the source goog.fx.DragDropItem object.
<a name="line1161"></a>   * @type {goog.fx.DragDropItem}
<a name="line1162"></a>   */
<a name="line1163"></a>  this.dragSourceItem = sourceItem;
<a name="line1164"></a>
<a name="line1165"></a>  /**
<a name="line1166"></a>   * Reference to the target goog.fx.AbstractDragDrop object.
<a name="line1167"></a>   * @type {goog.fx.AbstractDragDrop|undefined}
<a name="line1168"></a>   */
<a name="line1169"></a>  this.dropTarget = opt_target;
<a name="line1170"></a>
<a name="line1171"></a>  /**
<a name="line1172"></a>   * Reference to the target goog.fx.DragDropItem object.
<a name="line1173"></a>   * @type {goog.fx.DragDropItem|undefined}
<a name="line1174"></a>   */
<a name="line1175"></a>  this.dropTargetItem = opt_targetItem;
<a name="line1176"></a>
<a name="line1177"></a>  /**
<a name="line1178"></a>   * The actual element of the drop target that is the target for this event.
<a name="line1179"></a>   * @type {Element|undefined}
<a name="line1180"></a>   */
<a name="line1181"></a>  this.dropTargetElement = opt_targetElement;
<a name="line1182"></a>
<a name="line1183"></a>  /**
<a name="line1184"></a>   * X-Position relative to the screen.
<a name="line1185"></a>   * @type {number|undefined}
<a name="line1186"></a>   */
<a name="line1187"></a>  this.clientX = opt_clientX;
<a name="line1188"></a>
<a name="line1189"></a>  /**
<a name="line1190"></a>   * Y-Position relative to the screen.
<a name="line1191"></a>   * @type {number|undefined}
<a name="line1192"></a>   */
<a name="line1193"></a>  this.clientY = opt_clientY;
<a name="line1194"></a>
<a name="line1195"></a>  /**
<a name="line1196"></a>   * X-Position relative to the viewport.
<a name="line1197"></a>   * @type {number|undefined}
<a name="line1198"></a>   */
<a name="line1199"></a>  this.viewportX = opt_x;
<a name="line1200"></a>
<a name="line1201"></a>  /**
<a name="line1202"></a>   * Y-Position relative to the viewport.
<a name="line1203"></a>   * @type {number|undefined}
<a name="line1204"></a>   */
<a name="line1205"></a>  this.viewportY = opt_y;
<a name="line1206"></a>
<a name="line1207"></a>  /**
<a name="line1208"></a>   * The subtarget that is currently active if a subtargeting function
<a name="line1209"></a>   * is supplied.
<a name="line1210"></a>   * @type {Object|undefined}
<a name="line1211"></a>   */
<a name="line1212"></a>  this.subtarget = opt_subtarget;
<a name="line1213"></a>};
<a name="line1214"></a>goog.inherits(goog.fx.DragDropEvent, goog.events.Event);
<a name="line1215"></a>
<a name="line1216"></a>
<a name="line1217"></a>/** @override */
<a name="line1218"></a>goog.fx.DragDropEvent.prototype.disposeInternal = function() {
<a name="line1219"></a>};
<a name="line1220"></a>
<a name="line1221"></a>
<a name="line1222"></a>
<a name="line1223"></a>/**
<a name="line1224"></a> * Class representing a source or target element for drag and drop operations.
<a name="line1225"></a> *
<a name="line1226"></a> * @param {Element|string} element Dom Node, or string representation of node
<a name="line1227"></a> *     id, to be used as drag source/drop target.
<a name="line1228"></a> * @param {Object=} opt_data Data associated with the source/target.
<a name="line1229"></a> * @throws Error If no element argument is provided or if the type is invalid
<a name="line1230"></a> * @extends {goog.events.EventTarget}
<a name="line1231"></a> * @constructor
<a name="line1232"></a> */
<a name="line1233"></a>goog.fx.DragDropItem = function(element, opt_data) {
<a name="line1234"></a>  goog.base(this);
<a name="line1235"></a>
<a name="line1236"></a>  /**
<a name="line1237"></a>   * Reference to drag source/target element
<a name="line1238"></a>   * @type {Element}
<a name="line1239"></a>   */
<a name="line1240"></a>  this.element = goog.dom.getElement(element);
<a name="line1241"></a>
<a name="line1242"></a>  /**
<a name="line1243"></a>   * Data associated with element.
<a name="line1244"></a>   * @type {Object|undefined}
<a name="line1245"></a>   */
<a name="line1246"></a>  this.data = opt_data;
<a name="line1247"></a>
<a name="line1248"></a>  /**
<a name="line1249"></a>   * Drag object the item belongs to.
<a name="line1250"></a>   * @type {goog.fx.AbstractDragDrop?}
<a name="line1251"></a>   * @private
<a name="line1252"></a>   */
<a name="line1253"></a>  this.parent_ = null;
<a name="line1254"></a>
<a name="line1255"></a>  /**
<a name="line1256"></a>   * Event handler for listeners on events that can initiate a drag.
<a name="line1257"></a>   * @type {!goog.events.EventHandler}
<a name="line1258"></a>   * @private
<a name="line1259"></a>   */
<a name="line1260"></a>  this.eventHandler_ = new goog.events.EventHandler(this);
<a name="line1261"></a>  this.registerDisposable(this.eventHandler_);
<a name="line1262"></a>
<a name="line1263"></a>  if (!this.element) {
<a name="line1264"></a>    throw Error(&#39;Invalid argument&#39;);
<a name="line1265"></a>  }
<a name="line1266"></a>};
<a name="line1267"></a>goog.inherits(goog.fx.DragDropItem, goog.events.EventTarget);
<a name="line1268"></a>
<a name="line1269"></a>
<a name="line1270"></a>/**
<a name="line1271"></a> * The current element being dragged. This is needed because a DragDropItem can
<a name="line1272"></a> * have multiple elements that can be dragged.
<a name="line1273"></a> * @type {Element}
<a name="line1274"></a> * @private
<a name="line1275"></a> */
<a name="line1276"></a>goog.fx.DragDropItem.prototype.currentDragElement_ = null;
<a name="line1277"></a>
<a name="line1278"></a>
<a name="line1279"></a>/**
<a name="line1280"></a> * Get the data associated with the source/target.
<a name="line1281"></a> * @return {Object|null|undefined} Data associated with the source/target.
<a name="line1282"></a> */
<a name="line1283"></a>goog.fx.DragDropItem.prototype.getData = function() {
<a name="line1284"></a>  return this.data;
<a name="line1285"></a>};
<a name="line1286"></a>
<a name="line1287"></a>
<a name="line1288"></a>/**
<a name="line1289"></a> * Gets the element that is actually draggable given that the given target was
<a name="line1290"></a> * attempted to be dragged. This should be overriden when the element that was
<a name="line1291"></a> * given actually contains many items that can be dragged. From the target, you
<a name="line1292"></a> * can determine what element should actually be dragged.
<a name="line1293"></a> *
<a name="line1294"></a> * @param {Element} target The target that was attempted to be dragged.
<a name="line1295"></a> * @return {Element} The element that is draggable given the target. If
<a name="line1296"></a> *     none are draggable, this will return null.
<a name="line1297"></a> */
<a name="line1298"></a>goog.fx.DragDropItem.prototype.getDraggableElement = function(target) {
<a name="line1299"></a>  return target;
<a name="line1300"></a>};
<a name="line1301"></a>
<a name="line1302"></a>
<a name="line1303"></a>/**
<a name="line1304"></a> * Gets the element that is currently being dragged.
<a name="line1305"></a> *
<a name="line1306"></a> * @return {Element} The element that is currently being dragged.
<a name="line1307"></a> */
<a name="line1308"></a>goog.fx.DragDropItem.prototype.getCurrentDragElement = function() {
<a name="line1309"></a>  return this.currentDragElement_;
<a name="line1310"></a>};
<a name="line1311"></a>
<a name="line1312"></a>
<a name="line1313"></a>/**
<a name="line1314"></a> * Gets all the elements of this item that are potentially draggable/
<a name="line1315"></a> *
<a name="line1316"></a> * @return {Array.&lt;Element&gt;} The draggable elements.
<a name="line1317"></a> */
<a name="line1318"></a>goog.fx.DragDropItem.prototype.getDraggableElements = function() {
<a name="line1319"></a>  return [this.element];
<a name="line1320"></a>};
<a name="line1321"></a>
<a name="line1322"></a>
<a name="line1323"></a>/**
<a name="line1324"></a> * Event handler for mouse down.
<a name="line1325"></a> *
<a name="line1326"></a> * @param {goog.events.BrowserEvent} event Mouse down event.
<a name="line1327"></a> * @private
<a name="line1328"></a> */
<a name="line1329"></a>goog.fx.DragDropItem.prototype.mouseDown_ = function(event) {
<a name="line1330"></a>  if (!event.isMouseActionButton()) {
<a name="line1331"></a>    return;
<a name="line1332"></a>  }
<a name="line1333"></a>
<a name="line1334"></a>  // Get the draggable element for the target.
<a name="line1335"></a>  var element = this.getDraggableElement(/** @type {Element} */ (event.target));
<a name="line1336"></a>  if (element) {
<a name="line1337"></a>    this.maybeStartDrag_(event, element);
<a name="line1338"></a>  }
<a name="line1339"></a>};
<a name="line1340"></a>
<a name="line1341"></a>
<a name="line1342"></a>/**
<a name="line1343"></a> * Sets the dragdrop to which this item belongs.
<a name="line1344"></a> * @param {goog.fx.AbstractDragDrop} parent The parent dragdrop.
<a name="line1345"></a> */
<a name="line1346"></a>goog.fx.DragDropItem.prototype.setParent = function(parent) {
<a name="line1347"></a>  this.parent_ = parent;
<a name="line1348"></a>};
<a name="line1349"></a>
<a name="line1350"></a>
<a name="line1351"></a>/**
<a name="line1352"></a> * Adds mouse move, mouse out and mouse up handlers.
<a name="line1353"></a> *
<a name="line1354"></a> * @param {goog.events.BrowserEvent} event Mouse down event.
<a name="line1355"></a> * @param {Element} element Element.
<a name="line1356"></a> * @private
<a name="line1357"></a> */
<a name="line1358"></a>goog.fx.DragDropItem.prototype.maybeStartDrag_ = function(event, element) {
<a name="line1359"></a>  var eventType = goog.events.EventType;
<a name="line1360"></a>  this.eventHandler_.
<a name="line1361"></a>      listen(element, eventType.MOUSEMOVE, this.mouseMove_, false).
<a name="line1362"></a>      listen(element, eventType.MOUSEOUT, this.mouseMove_, false);
<a name="line1363"></a>
<a name="line1364"></a>  // Capture the MOUSEUP on the document to ensure that we cancel the start
<a name="line1365"></a>  // drag handlers even if the mouse up occurs on some other element. This can
<a name="line1366"></a>  // happen for instance when the mouse down changes the geometry of the element
<a name="line1367"></a>  // clicked on (e.g. through changes in activation styling) such that the mouse
<a name="line1368"></a>  // up occurs outside the original element.
<a name="line1369"></a>  var doc = goog.dom.getOwnerDocument(element);
<a name="line1370"></a>  this.eventHandler_.listen(doc, eventType.MOUSEUP, this.mouseUp_, true);
<a name="line1371"></a>
<a name="line1372"></a>  this.currentDragElement_ = element;
<a name="line1373"></a>
<a name="line1374"></a>  this.startPosition_ = new goog.math.Coordinate(
<a name="line1375"></a>      event.clientX, event.clientY);
<a name="line1376"></a>
<a name="line1377"></a>  event.preventDefault();
<a name="line1378"></a>};
<a name="line1379"></a>
<a name="line1380"></a>
<a name="line1381"></a>/**
<a name="line1382"></a> * Event handler for mouse move. Starts drag operation if moved more than the
<a name="line1383"></a> * threshold value.
<a name="line1384"></a> *
<a name="line1385"></a> * @param {goog.events.BrowserEvent} event Mouse move or mouse out event.
<a name="line1386"></a> * @private
<a name="line1387"></a> */
<a name="line1388"></a>goog.fx.DragDropItem.prototype.mouseMove_ = function(event) {
<a name="line1389"></a>  var distance = Math.abs(event.clientX - this.startPosition_.x) +
<a name="line1390"></a>      Math.abs(event.clientY - this.startPosition_.y);
<a name="line1391"></a>  // Fire dragStart event if the drag distance exceeds the threshold or if the
<a name="line1392"></a>  // mouse leave the dragged element.
<a name="line1393"></a>  // TODO(user): Consider using the goog.fx.Dragger to track the distance
<a name="line1394"></a>  // even after the mouse leaves the dragged element.
<a name="line1395"></a>  var currentDragElement = this.currentDragElement_;
<a name="line1396"></a>  var distanceAboveThreshold =
<a name="line1397"></a>      distance &gt; goog.fx.AbstractDragDrop.initDragDistanceThreshold;
<a name="line1398"></a>  var mouseOutOnDragElement = event.type == goog.events.EventType.MOUSEOUT &amp;&amp;
<a name="line1399"></a>      event.target == currentDragElement;
<a name="line1400"></a>  if (distanceAboveThreshold || mouseOutOnDragElement) {
<a name="line1401"></a>    this.eventHandler_.removeAll();
<a name="line1402"></a>    this.parent_.startDrag(event, this);
<a name="line1403"></a>  }
<a name="line1404"></a>};
<a name="line1405"></a>
<a name="line1406"></a>
<a name="line1407"></a>/**
<a name="line1408"></a> * Event handler for mouse up. Removes mouse move, mouse out and mouse up event
<a name="line1409"></a> * handlers.
<a name="line1410"></a> *
<a name="line1411"></a> * @param {goog.events.BrowserEvent} event Mouse up event.
<a name="line1412"></a> * @private
<a name="line1413"></a> */
<a name="line1414"></a>goog.fx.DragDropItem.prototype.mouseUp_ = function(event) {
<a name="line1415"></a>  this.eventHandler_.removeAll();
<a name="line1416"></a>  delete this.startPosition_;
<a name="line1417"></a>  this.currentDragElement_ = null;
<a name="line1418"></a>};
<a name="line1419"></a>
<a name="line1420"></a>
<a name="line1421"></a>
<a name="line1422"></a>/**
<a name="line1423"></a> * Class representing an active drop target
<a name="line1424"></a> *
<a name="line1425"></a> * @param {goog.math.Box} box Box describing the position and dimension of the
<a name="line1426"></a> *     target item.
<a name="line1427"></a> * @param {goog.fx.AbstractDragDrop=} opt_target Target that contains the item
<a name="line1428"></a>       associated with position.
<a name="line1429"></a> * @param {goog.fx.DragDropItem=} opt_item Item associated with position.
<a name="line1430"></a> * @param {Element=} opt_element Element of item associated with position.
<a name="line1431"></a> * @constructor
<a name="line1432"></a> * @private
<a name="line1433"></a> */
<a name="line1434"></a>goog.fx.ActiveDropTarget_ = function(box, opt_target, opt_item, opt_element) {
<a name="line1435"></a>
<a name="line1436"></a>  /**
<a name="line1437"></a>   * Box describing the position and dimension of the target item
<a name="line1438"></a>   * @type {goog.math.Box}
<a name="line1439"></a>   * @private
<a name="line1440"></a>   */
<a name="line1441"></a>  this.box_ = box;
<a name="line1442"></a>
<a name="line1443"></a>  /**
<a name="line1444"></a>   * Target that contains the item associated with position
<a name="line1445"></a>   * @type {goog.fx.AbstractDragDrop|undefined}
<a name="line1446"></a>   * @private
<a name="line1447"></a>   */
<a name="line1448"></a>  this.target_ = opt_target;
<a name="line1449"></a>
<a name="line1450"></a>  /**
<a name="line1451"></a>   * Item associated with position
<a name="line1452"></a>   * @type {goog.fx.DragDropItem|undefined}
<a name="line1453"></a>   * @private
<a name="line1454"></a>   */
<a name="line1455"></a>  this.item_ = opt_item;
<a name="line1456"></a>
<a name="line1457"></a>  /**
<a name="line1458"></a>   * The draggable element of the item associated with position.
<a name="line1459"></a>   * @type {Element|undefined}
<a name="line1460"></a>   * @private
<a name="line1461"></a>   */
<a name="line1462"></a>  this.element_ = opt_element;
<a name="line1463"></a>};
<a name="line1464"></a>
<a name="line1465"></a>
<a name="line1466"></a>/**
<a name="line1467"></a> * If this target is in a scrollable container this is it.
<a name="line1468"></a> * @type {goog.fx.ScrollableContainer_}
<a name="line1469"></a> * @private
<a name="line1470"></a> */
<a name="line1471"></a>goog.fx.ActiveDropTarget_.prototype.scrollableContainer_ = null;
<a name="line1472"></a>
<a name="line1473"></a>
<a name="line1474"></a>
<a name="line1475"></a>/**
<a name="line1476"></a> * Class for representing a scrollable container
<a name="line1477"></a> * @param {Element} element the scrollable element.
<a name="line1478"></a> * @constructor
<a name="line1479"></a> * @private
<a name="line1480"></a> */
<a name="line1481"></a>goog.fx.ScrollableContainer_ = function(element) {
<a name="line1482"></a>
<a name="line1483"></a>  /**
<a name="line1484"></a>   * The targets that lie within this container.
<a name="line1485"></a>   * @type {Array.&lt;goog.fx.ActiveDropTarget_&gt;}
<a name="line1486"></a>   * @private
<a name="line1487"></a>   */
<a name="line1488"></a>  this.containedTargets_ = [];
<a name="line1489"></a>
<a name="line1490"></a>  /**
<a name="line1491"></a>   * The element that is this container
<a name="line1492"></a>   * @type {Element}
<a name="line1493"></a>   * @private
<a name="line1494"></a>   */
<a name="line1495"></a>  this.element_ = element;
<a name="line1496"></a>
<a name="line1497"></a>  /**
<a name="line1498"></a>   * The saved scroll left location for calculating deltas.
<a name="line1499"></a>   * @type {number}
<a name="line1500"></a>   * @private
<a name="line1501"></a>   */
<a name="line1502"></a>  this.savedScrollLeft_ = 0;
<a name="line1503"></a>
<a name="line1504"></a>  /**
<a name="line1505"></a>   * The saved scroll top location for calculating deltas.
<a name="line1506"></a>   * @type {number}
<a name="line1507"></a>   * @private
<a name="line1508"></a>   */
<a name="line1509"></a>  this.savedScrollTop_ = 0;
<a name="line1510"></a>
<a name="line1511"></a>  /**
<a name="line1512"></a>   * The space occupied by the container.
<a name="line1513"></a>   * @type {goog.math.Box}
<a name="line1514"></a>   * @private
<a name="line1515"></a>   */
<a name="line1516"></a>  this.box_ = null;
<a name="line1517"></a>};
</pre>


</body>
</html>
